package com.maint.m.glsurface

import android.media.MediaCodec
import android.media.MediaCodecInfo
import android.media.MediaCodecList
import android.media.MediaFormat
import android.os.Build
import android.os.Handler
import android.os.Looper
import android.util.Log
import java.io.File
import java.io.FileOutputStream
import java.nio.ByteBuffer

// H264数据回调接口
interface OnH264DataListener {
    fun onH264Data(data: ByteArray)
    fun onH264Data(data: ByteArray, width: Int, height: Int, presentationTimeUs: Long)
}

class NV21ToH264Encoder(
    private val width: Int,
    private val height: Int,
    private val outputFile: File
) {
    private val TAG = "NV21ToH264Encoder"
    private var codec: MediaCodec? = null
    private var fos: FileOutputStream? = null
    // 回调监听器
    var h264DataListener: OnH264DataListener? = null
    private val mainHandler = Handler(Looper.getMainLooper())
    
    // 编码成功的帧数统计
    private var encodedFrameCount = 0
    private var isRunning = false
    private var isFirstFrame = true // 标记是否是第一帧，用于特殊处理
    private var spsPpsSent = false // 标记SPS/PPS是否已发送
    private var spsPpsData: ByteArray? = null // 缓存SPS/PPS数据，以便在需要时重新发送

    fun start() {
        try {
            fos = FileOutputStream(outputFile)

            val format = MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC, width, height)
            // 尝试选择最适合NV21格式的颜色格式
            // 首先检查设备支持的颜色格式
            var colorFormat = MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible // 使用灵活格式作为默认值
            
            try {
                // 遍历所有编码器，查找支持AVC编码的编码器
                for (codecInfo in MediaCodecList(MediaCodecList.REGULAR_CODECS).codecInfos) {
                    if (!codecInfo.isEncoder) continue
                    
                    try {
                        val capabilities = codecInfo.getCapabilitiesForType(MediaFormat.MIMETYPE_VIDEO_AVC)
                        val supportedColorFormats = capabilities.colorFormats
                        
                        // 优先选择NV21兼容的格式
            for (colorFormatValue in supportedColorFormats) {
                when (colorFormatValue) {
                    MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar,
                    MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible -> {
                        colorFormat = colorFormatValue
                        break
                    }
                }
            }
                        break // 找到合适的编码器就退出循环
                    } catch (e: Exception) {
                        // 忽略不支持AVC编码的编码器
                        continue
                    }
                }
            } catch (e: Exception) {
                Log.w(TAG, "获取编码器支持的颜色格式失败，使用默认值", e)
            }
            
            // 使用选择的颜色格式
            format.setInteger(MediaFormat.KEY_COLOR_FORMAT, colorFormat)
            
            Log.i(TAG, "编码器初始化: ${width}x${height}, 格式: AVC, 颜色格式: $colorFormat")
            
            // 调整比特率，避免过大
            format.setInteger(MediaFormat.KEY_BIT_RATE, width * height * 2) // 降低比特率以减少资源需求
            format.setInteger(MediaFormat.KEY_FRAME_RATE, 15) // 降低帧率以减少处理负载
            format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1) // 更频繁地生成关键帧，确保SPS/PPS被及时发送
            
            // 添加编码器性能相关参数
            format.setInteger(MediaFormat.KEY_MAX_B_FRAMES, 0) // 禁用B帧以降低延迟
            
            // 确保生成SPS和PPS
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                format.setInteger(MediaFormat.KEY_PUSH_BLANK_BUFFERS_ON_STOP, 1) // 停止时推送空白缓冲区
                format.setInteger(MediaFormat.KEY_OPERATING_RATE, 15 * 1000) // 调整操作速率
                format.setInteger(MediaFormat.KEY_MAX_B_FRAMES, 0) // 禁用B帧以降低延迟
            }
            
            // 添加额外的参数以确保SPS/PPS正确生成
            // 使用数值常量而不是枚举，以避免兼容性问题
            format.setInteger(MediaFormat.KEY_COMPLEXITY, 0) // 低复杂度编码
            format.setInteger(MediaFormat.KEY_PRIORITY, 0) // 正常优先级

            codec = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_VIDEO_AVC)
            codec?.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE)
            codec?.start()
            
            isRunning = true
            isFirstFrame = true
            spsPpsSent = false
            spsPpsData = null
            encodedFrameCount = 0
            Log.i(TAG, "编码器已启动: ${width}x${height}")
        } catch (e: Exception) {
            Log.e(TAG, "启动编码器失败", e)
            stop() // 确保资源被释放
        }
    }

    fun encodeFrame(nv21: ByteArray) {
        try {
            if (codec == null || !isRunning) {
                Log.w(TAG, "编码器未初始化或未运行，跳过编码")
                return
            }

            // 检查数据有效性，确保不会发生BufferOverflowException
            val expectedSize = width * height * 3 / 2
            if (nv21.size < expectedSize) {
                Log.e(TAG, "NV21数据大小不足，期望: $expectedSize, 实际: ${nv21.size}")
                return
            }

            val bufferInfo = MediaCodec.BufferInfo()

            val inputIndex = codec?.dequeueInputBuffer(1000) ?: -1 // 设置1ms超时，避免长时间阻塞
            if (inputIndex >= 0) {
                try {
                    // 使用较新的getInputBuffer API替代已弃用的inputBuffers
                    val inputBuffer = codec?.getInputBuffer(inputIndex)
                    if (inputBuffer != null) {
                        inputBuffer.clear()

                        // NV21格式需要转换为编码器支持的格式
                        val colorFormat = getCurrentColorFormat()
                        val encodedData: ByteArray = when {
                            isFormatNV21Compatible(colorFormat) -> {
                                // 如果编码器直接支持NV21相关格式，则直接使用
                                nv21
                            }
                            else -> {
                                // 否则转换为YUV420P格式
                                convertNV21ToYUV420P(nv21, width, height)
                            }
                        }

                        // 安全检查：确保缓冲区有足够空间
                        val maxBytesToPut = Math.min(encodedData.size, inputBuffer.remaining())
                        if (maxBytesToPut > 0) {
                            inputBuffer.put(encodedData, 0, maxBytesToPut)
                            
                            // 设置适当的帧标记
                            var flags = 0
                            if (isFirstFrame) {
                                flags = MediaCodec.BUFFER_FLAG_KEY_FRAME
                                Log.d(TAG, "第一帧编码，强制请求SPS/PPS配置")
                            }
                            
                            codec?.queueInputBuffer(inputIndex, 0, maxBytesToPut, computePresentationTime(encodedFrameCount), flags)
                            Log.d(TAG, "帧 ${encodedFrameCount}: 放入输入缓冲区 ${maxBytesToPut} 字节, 标记: $flags, 颜色格式: $colorFormat")
                            if (isFirstFrame) {
                                Log.i(TAG, "第一帧处理完成，应生成SPS/PPS配置")
                                isFirstFrame = false
                            }
                        } else {
                            Log.e(TAG, "输入缓冲区没有可用空间")
                            codec?.queueInputBuffer(inputIndex, 0, 0, 0, 0) // 只释放缓冲区，不标记结束流
                        }
                    }
                } catch (e: Exception) {
                    Log.e(TAG, "处理输入缓冲区异常", e)
                    // 确保释放缓冲区
                    try {
                        codec?.queueInputBuffer(inputIndex, 0, 0, 0, 0)
                    } catch (inner: Exception) {
                        Log.e(TAG, "释放输入缓冲区失败", inner)
                    }
                }
            }

            var outputIndex = codec?.dequeueOutputBuffer(bufferInfo, 1000) ?: -1
            while (outputIndex >= 0) {
                try {
                    // 修复：使用较新的getOutputBuffer API替代已弃用的outputBuffers
                    val outputBuffer = codec?.getOutputBuffer(outputIndex)
                    if (outputBuffer != null && bufferInfo.size > 0) {
                        // 确保缓冲区有效且有数据
                        val outData = ByteArray(bufferInfo.size)
                        // 保存当前position，读取后恢复
                        val position = outputBuffer.position()
                        outputBuffer.get(outData)
                        outputBuffer.position(position) // 恢复position，避免影响后续操作
                        
                        // 详细检查输出帧类型
                        val isConfigFrame = (bufferInfo.flags and MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0
                        val isKeyFrame = (bufferInfo.flags and MediaCodec.BUFFER_FLAG_KEY_FRAME) != 0
                        val isEndOfStream = (bufferInfo.flags and MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0
                        
                        // 记录帧类型和基本信息
                        if (isConfigFrame) {
                            // 这是SPS/PPS配置帧
                            Log.i(TAG, "检测到SPS/PPS配置帧: ${outData.size}字节")
                            spsPpsData = outData.clone() // 缓存SPS/PPS数据
                            spsPpsSent = true
                            
                            // 对配置帧进行特殊处理，确保SPS/PPS被优先处理
                            if (h264DataListener != null) {
                                val presentationTimeUs = bufferInfo.presentationTimeUs
                                mainHandler.post {  
                                    try {
                                        Log.i(TAG, "发送SPS/PPS配置帧到回调")
                                        h264DataListener?.onH264Data(outData)
                                        h264DataListener?.onH264Data(outData, width, height, presentationTimeUs)
                                    } catch (e: Exception) {
                                        Log.e(TAG, "SPS/PPS配置帧回调异常", e)
                                    }
                                }
                            }
                        } else if (isKeyFrame) {
                            Log.i(TAG, "检测到关键帧: ${outData.size}字节, 时间戳: ${bufferInfo.presentationTimeUs}")
                            
                            // 如果关键帧但还没有发送SPS/PPS，先重新发送SPS/PPS
                            if (!spsPpsSent && spsPpsData != null) {
                                Log.i(TAG, "关键帧前重新发送SPS/PPS配置帧")
                                if (h264DataListener != null) {
                                    mainHandler.post {  
                                        try {
                                            h264DataListener?.onH264Data(spsPpsData!!)
                                            h264DataListener?.onH264Data(spsPpsData!!, width, height, bufferInfo.presentationTimeUs - 1000)
                                        } catch (e: Exception) {
                                            Log.e(TAG, "重新发送SPS/PPS异常", e)
                                        }
                                    }
                                }
                            }
                        } else if (isEndOfStream) {
                            Log.i(TAG, "检测到流结束帧")
                        } else {
                            Log.d(TAG, "检测到P帧: ${outData.size}字节")
                            
                            // 确保P帧只有在SPS/PPS已发送后才被处理
                            if (!spsPpsSent) {
                                Log.w(TAG, "警告: P帧在SPS/PPS配置帧之前收到，可能导致解码错误")
                            }
                        }
                        
                        // 检查是否是H264数据的开始字节（NAL单元开始码）
                        if (outData.size >= 4) {
                            val startCode = String.format("%02x%02x%02x%02x", outData[0], outData[1], outData[2], outData[3])
                            if (startCode == "00000001" || startCode == "00000100") {
                                Log.d(TAG, "检测到NAL单元开始码: $startCode")
                            }
                        }

                        // 写入文件
                        try {
                            fos?.write(outData)
                        } catch (e: Exception) {
                            Log.e(TAG, "写入H264数据到文件失败", e)
                        }
                        
                        // 配置帧已经单独处理，这里只处理视频帧
                        if (!isConfigFrame && outData.isNotEmpty() && h264DataListener != null) {
                            val presentationTimeUs = bufferInfo.presentationTimeUs
                            mainHandler.post {  
                                try {
                                    h264DataListener?.onH264Data(outData)
                                    h264DataListener?.onH264Data(outData, width, height, presentationTimeUs)
                                    encodedFrameCount++
                                    Log.d(TAG, "成功回调H264数据，帧号: $encodedFrameCount, 类型: ${if (isKeyFrame) "关键帧" else "P帧"}")
                                } catch (e: Exception) {
                                    Log.e(TAG, "H264数据回调异常", e)
                                }
                            }
                        }
                    }
                } catch (e: Exception) {
                    Log.e(TAG, "处理输出缓冲区异常", e)
                } finally {
                    // 确保无论如何都释放输出缓冲区
                    try {
                        codec?.releaseOutputBuffer(outputIndex, false)
                    } catch (e: Exception) {
                        Log.e(TAG, "释放输出缓冲区失败", e)
                    }
                }
                outputIndex = codec?.dequeueOutputBuffer(bufferInfo, 0) ?: -1
            }
        } catch (e: Exception) {
            Log.e(TAG, "编码帧处理异常", e)
        }
    }

    fun stop() {
        try {
            isRunning = false
            spsPpsSent = false
            spsPpsData = null
            
            // 安全停止编码器
            try {
                codec?.stop()
            } catch (e: Exception) {
                Log.e(TAG, "停止编码器异常", e)
            }
            try {
                codec?.release()
            } catch (e: Exception) {
                Log.e(TAG, "释放编码器异常", e)
            }
            codec = null
            
            // 关闭文件输出流
            try {
                fos?.flush()
                fos?.close()
            } catch (e: Exception) {
                Log.e(TAG, "关闭文件输出流异常", e)
            }
            fos = null
            
            Log.i(TAG, "编码器已停止，共编码 ${encodedFrameCount} 帧")
        } catch (e: Exception) {
            Log.e(TAG, "停止编码器时发生异常", e)
        }
    }

    /** NV21 -> NV12 转换 */
    private fun nv21ToNv12(nv21: ByteArray, width: Int, height: Int): ByteArray {
        try {
            val nv12 = ByteArray(nv21.size)
            val frameSize = width * height
            System.arraycopy(nv21, 0, nv12, 0, frameSize) // Y 直接复制

            var i = 0
            while (i < frameSize / 2) {
                nv12[frameSize + i] = nv21[frameSize + i xor 1] // UV 对调
                i += 2
            }
            return nv12
        } catch (e: Exception) {
            Log.e(TAG, "NV21转NV12失败", e)
            throw e // 重新抛出异常，避免返回错误数据
        }
    }
    
    /** 获取当前编码器使用的颜色格式 */
    private fun getCurrentColorFormat(): Int {
        // 简化实现，直接返回默认值以避免编译错误
        return MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar
    }
    
    /** 检查颜色格式是否与NV21兼容 */
    private fun isFormatNV21Compatible(colorFormat: Int): Boolean {
        return when (colorFormat) {
            MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar,
            MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible -> true
            else -> false
        }
    }
    
    /** 转换NV21格式到YUV420P平面格式 */
    private fun convertNV21ToYUV420P(nv21: ByteArray, width: Int, height: Int): ByteArray {
        val frameSize = width * height
        val yuv420p = ByteArray(frameSize * 3 / 2)
        
        try {
            // 复制Y分量
            System.arraycopy(nv21, 0, yuv420p, 0, frameSize)
            
            // 分离UV分量
            var uIndex = frameSize
            var vIndex = frameSize + frameSize / 4
            
            for (i in 0 until frameSize / 2 step 2) {
                yuv420p[uIndex++] = nv21[frameSize + i + 1] // U分量
                yuv420p[vIndex++] = nv21[frameSize + i]     // V分量
            }
        } catch (e: Exception) {
            Log.e(TAG, "NV21转换到YUV420P失败", e)
            return nv21 // 失败时返回原始数据
        }
        
        return yuv420p
    }
    
    /** 获取编码器列表 */
    private fun getCodecList(): List<MediaCodecInfo> {
        try {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                return MediaCodecList(MediaCodecList.REGULAR_CODECS).codecInfos.asList()
            }
        } catch (e: Exception) {
            Log.w(TAG, "获取编码器列表失败", e)
        }
        return emptyList()
    }
    
    /** 计算帧的展示时间戳，使用实际帧率15fps */
    private fun computePresentationTime(frameIndex: Int): Long {
        return (frameIndex * 1000000.0 / 15.0).toLong()
    }
    
    /** 获取当前编码统计信息 */
    fun getEncodingStats(): EncodingStats {
        return EncodingStats(
            encodedFrameCount = encodedFrameCount,
            isRunning = isRunning,
            width = width,
            height = height,
            frameRate = 15,
            bitRate = width * height * 2
        )
    }
    
    /** 编码统计数据类 */
    data class EncodingStats(
        val encodedFrameCount: Int,
        val isRunning: Boolean,
        val width: Int,
        val height: Int,
        val frameRate: Int,
        val bitRate: Int
    )
}
